package main

import "fmt"

/*
1、方法的声明
func (recevier type) methodName(参数列表) (返回值列表){
	方法体
	return 返回值
}
(1)参数列表：表示方法输入
(2)recevier type：表示这个方法和type这个类型进行绑定，或者说该方法作用于type类型
(3)recevier type：type可以是结构体，也可以其它的自定义类型
(4)recevier：就是type类型的一个变量（实例），比如：Person结构体的一个变量（实例）
(5)返回值列表：表示返回的值，可以多个
(6)方法主体：表示为了实现某一功能代码块
(7)return语句不是必须的
2、方法注意事项
(1)结构体类型是值类型，在方法调用中，遵守值类型的传递机制，是值拷贝传递方式
(2)如程序员希望在方法中，修改结构体变量的值，可以通过结构体指针的方式来处理
(3)go中的方法作用在指定的数据类型上的（即：和指定的数据类型绑定），因此自定义类型，都可以有方法，而不仅仅是struct，比如int，float32等都可以有方法
(4)方法的访问范围控制的规则，和函数一样，方法名首字母小写，只能在本包访问，方法首字母大写，可以在本包和其他包访问
(5)如果一个变量实现了String()这个方法，那么fmt.Println默认会调用这个变量的String()进行输出
*/
type Circle struct {
	radius float64
}

//2(2)
//为了提高效率，通常方法和结构体的指针类型绑定
func (c *Circle) area() float64 {
	c.radius = 10
	return 3.14 * (*c).radius * (*c).radius
}

//2(3)
type integer int

func (i integer) print() {
	fmt.Println("i=", i)
}
func (i *integer) change() {
	*i = *i + 1
}

//2(5)
type Student struct {
	Name string
	Age  int
}

func (stu *Student) String() string { //这里一定要定义成String方法
	str := fmt.Sprintf("Name=[%v] Age=[%v]", stu.Name, stu.Age)
	return str
}
func main() {
	//2(2)
	var c Circle
	c.radius = 5.0
	// res := (&c).area()
	//编译器底层做了优化，(&c).area()等价c.area()
	//因为编译器会自动的给加上&c
	res := c.area()
	fmt.Println("res=", res)
	fmt.Println("c.radius=", c.radius)

	//2(3)
	var i integer = 10
	i.print()
	i.change()
	fmt.Println("i=", i)

	//2(5)
	stu := Student{
		Name: "tom",
		Age:  20,
	}
	//如果实现了*Student类型的String方法，就会自动调用
	fmt.Println(&stu) //传入地址，会自动调用String()方法
}
